﻿using System;
using System.Collections.Generic;
using System.Linq;
using Xenta.Api;
using Xenta.Entities;
using Xenta.Enums;
using Xenta.Security;
using Xenta.Structs;
using Xenta.Utils;

namespace Xenta.Operations
{
    #region __General__

    /// <summary>
    /// Creates an setting.
    /// </summary>
    public class CreateConfigParam : CreateAuditable<SettingEntity>
    {
        #region Properties

        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        public string Key
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        public string Value
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(String.IsNullOrWhiteSpace(Key))
                return Err.Of<SettingEntity>().NotValid("Key");
            return base.Validate(uow);
        }

        protected override void Construct(IUnitOfWork uow, SettingEntity entity)
        {
            base.Construct(uow, entity);

            entity.Key = Key.TrimToLen(100);
            entity.Value = StringHelper.EnsureNotNull(Value).TrimToLen(1000);
        }

        #endregion
    }

    /// <summary>
    /// Updates the setting.
    /// </summary>
    public class UpdateConfigParam : UpdateAuditable<SettingEntity>
    {
        #region Properties

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        public string Value
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Revise(IUnitOfWork uow, SettingEntity entity)
        {
            base.Revise(uow, entity);

            entity.Value = StringHelper.EnsureNotNull(Value).TrimToLen(1000);
        }

        #endregion
    }

    /// <summary>
    /// Sets the setting.
    /// </summary>
    public class SetConfigParam : Operation<SettingEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SYS");
            }
        }

        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        public string Key
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        public string Value
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out SettingEntity result)
        {
            var entity = uow.Execute(new GetConfigParamByKey
            {
                Key = Key
            }).Result;

            if(entity == null)
            {
                entity = uow.Execute(new CreateConfigParam
                {
                    Key = Key,
                    Value = Value
                }).Result;
            }
            else
            {
                entity = uow.Execute(new UpdateConfigParam
                {
                    EntityID = entity.EntityID,
                    Value = Value
                }).Result;
            }

            result = entity;
        }

        #endregion
    }

    /// <summary>
    /// Deletes the setting.
    /// </summary>
    public class DeleteConfigParam : DeleteEntity<SettingEntity>
    {
    }

    /// <summary>
    /// Gets the setting by identifier.
    /// </summary>
    public class GetConfigParam : GetEntity<SettingEntity>,
        IApiOperation
    {
    }

    /// <summary>
    /// Gets the setting by key.
    /// </summary>
    public class GetConfigParamByKey : QueryEntity<SettingEntity>,
        IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets or sets the setting key.
        /// </summary>
        public string Key
        {
            get;
            set;
        }

        #endregion

        #region Options

        protected override bool Cacheable
        {
            get
            {
                return true;
            }
        }

        #endregion

        #region Utilities

        protected override IQueryable<SettingEntity> Build(IUnitOfWork uow, IQueryable<SettingEntity> query)
        {
            string key = StringHelper.EnsureNotNull(Key).TrimToLen(100);
            query = base.Build(uow, query).Where(x => x.Key.Equals(key));
            return query;
        }

        #endregion
    }

    /// <summary>
    /// Gets the setting value by key.
    /// </summary>
    public class GetConfigParamValueByKey : Operation<String>,
        IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets or sets the setting key.
        /// </summary>
        public string Key
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out string result)
        {
            result = String.Empty;
            var entity = uow.Execute(new GetConfigParamByKey
            {
                Key = Key
            }).Result;
            if(entity == null) 
                return;
            result = entity.Value;
        }

        /// <summary>
        /// Gets the result converted into type T.
        /// </summary>
        /// <typeparam name="T">The target type to convert.</typeparam>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>The result as type T.</returns>
        public T ResultAs<T>(T defaultValue = default(T))
        {
            return Result.ParseAs(defaultValue);
        }

        #endregion
    }

    #endregion

    #region __Search__

    /// <summary>
    /// Search over setting collection.
    /// </summary>
    public class SearchConfigParams : SearchOperation<SettingEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public SearchConfigParams()
        {
            Term = SearchTerm.Empty;
            SortDir = SortDirection.Ascending;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SYS");
            }
        }

        /// <summary>
        /// Gets or sets the search term.
        /// </summary>
        public SearchTerm Term
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the sort direction.
        /// </summary>
        public SortDirection SortDir
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override IQueryable<SettingEntity> Build(IUnitOfWork uow, IQueryable<SettingEntity> query)
        {
            query = base.Build(uow, query);
            switch(Term.Mode)
            {
                case SearchTerm.SearchMode.StartsWith:
                    query = query.Where(x => x.Key.StartsWith(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.EndsWith:
                    query = query.Where(x => x.Key.EndsWith(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.Contains:
                    query = query.Where(x => x.Key.Contains(Term.Keyword) ||
                        x.Value.Contains(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.Equals:
                    query = query.Where(x => x.Key.Equals(Term.Keyword));
                    break;
            }
            query = query.OrderBy(x => x.Key, SortDir);
            return query;
        }

        #endregion
    }

    /// <summary>
    /// Gets the collection of settings as a dictionary, where 
    /// key - setting key and value - setting value.
    /// </summary>
    public class GetConfigParamDictionary : SearchOperation<SettingEntity, String, String>,
        IApiOperation
    {
        #region Options

        protected override bool Cacheable
        {
            get
            {
                return true;
            }
        }

        #endregion

        #region Utilities

        protected override IQueryable<SettingEntity> Build(IUnitOfWork uow, IQueryable<SettingEntity> query)
        {
            return base.Build(uow, query).OrderBy(x => x.Key);
        }

        protected override IQueryable<KeyValuePair<String, String>> Map(IQueryable<SettingEntity> query)
        {
            return query.Select(x => new KeyValuePair<String, String>(x.Key, x.Value));
        }

        #endregion
    }

    #endregion

    #region __Bulk__

    /// <summary>
    /// Updates the configuration settings from dictionary.
    /// </summary>
    public class BulkUpdateConfigParams : Operation,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("SYS");
            }
        }

        /// <summary>
        /// Gets or sets the setting dictionary.
        /// </summary>
        public IDictionary<String, String> Settings
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(Settings == null || !Settings.Any())
                return Err.Of(this).No("Settings");
            return base.Validate(uow);
        }

        protected override void Work(IUnitOfWork uow)
        {
            foreach(var i in Settings)
            {
                uow.Execute(new SetConfigParam
                {
                    Key = i.Key,
                    Value = i.Value
                });
            }
        }

        #endregion
    }

    #endregion
}
